/*
 *
 */
package com.ePadink;


import java.awt.Canvas;
import java.awt.Color;
import java.awt.Image;
import java.awt.image.PixelGrabber;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Vector;

class ImageToGif extends Canvas
{
  private static final int TABLESIZE = 5003;
  private static final int COLOR_MAX = 256;
  private Image image;
  private OutputStream output;
  private DataOutputStream dataOut;
  private int palSize;
  private int lzwData;
  private int[] palArr;
  private byte flagLSD;
  private short sOriginalCodeSize;
  private short sActCodeSize;
  private short clearCode;
  private short endCode;
  private short freeSlot;
  private short lzwBits;
  private short BlockPos;
  private short imgWidth;
  private short imgHeight;
  private short[] code;
  private short[] prefix;
  private short[] Block;
  private short[] pixCol;
  private short[] codeCharacter;
  private boolean message;

  public ImageToGif(Image image1, OutputStream outputstream, boolean flag)
    throws IOException
  {
    this.image = image1;
    this.output = outputstream;
    this.message = flag;
    startProc();
  }

  public void startProc()
  {
    try
    {
      this.code = new short[5003];
      this.prefix = new short[5003];
      this.codeCharacter = new short[5003];
      this.Block = new short[256];
      if ((this.image != null) && (getImageInfo()) && (openGif()) && (calcGif()))
      {
        if (closeGif())
        {
          if (!this.message);
        }
        else if (this.message)
          System.out.println("\n Error, Picture is NOT available!");
        return;
      }
    }
    catch (Exception exception)
    {
      System.out.println(String.valueOf(exception));
    }
  }

  public boolean getImageInfo()
  {
    int i1 = 0;
    int j1 = 0;
    int k1 = 0;
    int[] ai1 = { 16777215, 16777215, 14737600, 14737632, 15790320, 16316664, 16579836, 16711422, 16777215, 16777215 };
    try
    {
      this.imgWidth = ((short)this.image.getWidth(this));
      this.imgHeight = ((short)this.image.getHeight(this));
      int l = this.imgWidth * this.imgHeight;
      int[] ai = new int[l];
      PixelGrabber pixelgrabber = new PixelGrabber(this.image, 0, 0, this.imgWidth, this.imgHeight, ai, 0, this.imgWidth);
      Vector vector = new Vector(256);
      Vector vector1 = new Vector(1);
      Integer[] ainteger = new Integer[0];
      Integer[] ainteger1 = new Integer[1];
      pixelgrabber.grabPixels();
      vector1.addElement(new Integer(0));
      while ((j1 <= 256) || (ai1[i1] == 16777215))
      {
        ainteger = new Integer[vector.size()];
        vector.copyInto(ainteger);
        k1 = j1;
        i1++;
        vector.removeAllElements();
        vector.addElement(new Integer(ai[0] & ai1[i1]));
        vector.addElement(new Integer(16777216));
        j1 = 2;
        this.palSize = 2;
        boolean flag1 = true;
        byte byte0 = 2;
        for (int l1 = 1; l1 < l; l1++) {
          int i = ai[l1] & ai1[i1];
          int j = this.palSize - 1;
          int k = this.palSize;
          boolean flag;
          do { vector1.setElementAt(vector.elementAt(j), 0);
            vector1.copyInto(ainteger1);

            if (i == ainteger1[0].intValue())
            {
              k = 0;
              flag = true;
            }
            else {
              k /= 2;
              if (i < ainteger1[0].intValue())
                j -= k;
              else
                j += k;
              flag = false;
            } }
          while (k > 0);
          if (!flag)
          {
            vector1.setElementAt(vector.elementAt(j), 0);
            vector1.copyInto(ainteger1);
            if (i < ainteger1[0].intValue())
              vector.insertElementAt(new Integer(ai[l1] & ai1[i1]), j);
            else
              vector.insertElementAt(new Integer(ai[l1] & ai1[i1]), j + 1);
            if (j1++ > 256)
              break;
            vector.removeElement(vector.lastElement());
            if (j1 > this.palSize)
            {
              for (int j2 = this.palSize; j2 < 2 * this.palSize; j2++) {
                vector.addElement(new Integer(16777216));
              }
              this.palSize *= 2;
            }
          }
        }
        j1--; if ((j1 <= 256) && (ai1[i1] == 16777215))
        {
          ainteger = new Integer[vector.size()];
          vector.copyInto(ainteger);
          k1 = j1;
        }
        else {
          if (((j1 > 256) && (ai1[i1] != 16777215)) || ((i1 > 3) && (ai1[i1] == 16777215))) break;
        }
      }
      i1--;
      this.palSize = k1;
      this.palArr = new int[this.palSize];
      for (int i2 = 0; i2 < this.palSize; i2++) {
        this.palArr[i2] = (ainteger[i2].intValue() | (ai1[i1] ^ 0xFFFFFF) >> 1 & (ai1[i1] ^ 0xFFFFFF));
      }
      this.pixCol = new short[l];
      for (int k2 = 0; k2 < l; k2++)
      {
        for (short word0 = 0; word0 < this.palSize; word0 = (short)(word0 + 1))
        {
          if ((ai[k2] & ai1[i1]) == (this.palArr[word0] & ai1[i1]))
          {
            this.pixCol[k2] = word0;
            break;
          }
        }
      }

    }
    catch (Exception _ex)
    {
      return false;
    }
    return true;
  }

  public boolean openGif()
    throws IOException
  {
    try
    {
      this.dataOut = new DataOutputStream(this.output);
    }
    catch (Exception _ex)
    {
      return false;
    }
    return true;
  }

  public char MSBtoLSB(short word0)
  {
    short word1 = (short)(word0 >> 8);
    short word2 = (short)((word0 & 0xFF) << 8);
    return (char)(word2 + word1);
  }

  public boolean calcGif()
  {
    try
    {
      return (writeHeader()) && (writeLSD()) && (writeGlobalPalette()) && (writeImageDescriptor()) && (writeDataBlocks());
    }
    catch (Exception _ex) {
    }
    return false;
  }

  public boolean writeDataBlocks()
  {
    int[] ai = { 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191 };
    try
    {
      int j = (this.flagLSD & 0x7) + 1;
      if (j > 2)
        this.sOriginalCodeSize = ((short)j);
      else
        this.sOriginalCodeSize = 2;
      this.dataOut.writeByte((byte)this.sOriginalCodeSize);
      CalcSpecialCodes();
      ClearCompressionTable();
      this.Block[0] = 0;
      this.BlockPos = 1;
      this.lzwData = 0;
      this.lzwBits = 0;
      if (!lzwOutput(this.clearCode))
        return false;
      int l = 0;
      int i = l * this.imgWidth;
      short word3 = (short)(this.pixCol[(i++)] & 0xFF);
      int k = 1;
      while (l < this.imgHeight)
      {
        short word2 = this.pixCol[(i++)];
        short word0 = FindSlot(word3, word2);
        if (this.code[word0] != -1)
        {
          word3 = this.code[word0];
        }
        else {
          if (this.freeSlot <= ai[this.sActCodeSize] + 1)
          {
            this.code[word0] = (this.freeSlot++);
            this.prefix[word0] = word3;
            this.codeCharacter[word0] = word2;
          }
          if (!lzwOutput(word3))
            return false;
          word3 = word2;
          if ((this.freeSlot > ai[this.sActCodeSize] + 1) || (this.freeSlot == 4096))
            if (this.sActCodeSize < 12)
            {
              this.sActCodeSize = ((short)(this.sActCodeSize + 1));
            }
            else {
              if (!lzwOutput(this.clearCode))
                return false;
              this.sActCodeSize = this.sOriginalCodeSize;
              CalcSpecialCodes();
              ClearCompressionTable();
            }
        }
        k++; if (k == this.imgWidth)
        {
          k = 0;
          l++; if (l < this.imgHeight)
            i = l * this.imgWidth;
        }
      }
      if (!lzwOutput(word3))
        return false;
      if (!lzwOutput((short)0))
        return false;
      if (!lzwOutput(this.endCode))
        return false;
      if (!lzwOutput((short)0))
        return false;
      if (this.Block[0] != 0)
      {
        this.dataOut.writeByte(this.Block[0]);
        for (short word1 = 1; word1 <= this.Block[0]; 
          this.dataOut.writeByte(this.Block[word1])) word1 = (short)(word1 + 1);

        this.dataOut.writeByte(0);
      }
      return true;
    }
    catch (Exception _ex) {
    }
    return false;
  }

  public void ClearCompressionTable()
  {
    for (short word0 = 0; word0 < 5003; word0 = (short)(word0 + 1))
      this.code[word0] = -1;
  }

  public short FindSlot(short word0, short word1)
  {
    short word2 = (short)(word1 << 4 ^ word0);
    short word3 = (short)(word2 != 0 ? 5003 - word2 : 1);
    while (true)
    {
      if (this.code[word2] == -1)
        return word2;
      if ((this.prefix[word2] == word0) && (this.codeCharacter[word2] == word1))
        return word2;
      word2 = (short)(word2 - word3);
      if (word2 < 0)
        word2 = (short)(word2 + 5003);
    }
  }

  public boolean lzwOutput(short word0)
  {
    try
    {
      this.lzwData |= word0 << this.lzwBits;
      for (this.lzwBits = ((short)(this.lzwBits + this.sActCodeSize)); this.lzwBits >= 8; )
      {
        this.Block[(this.BlockPos++)] = ((short)(byte)(this.lzwData & 0xFF));
        int tmp70_69 = 0;
        short[] tmp70_66 = this.Block; tmp70_66[tmp70_69] = ((short)(tmp70_66[tmp70_69] + 1));
        this.lzwData >>= 8;
        this.lzwBits = ((short)(this.lzwBits - 8));
        if (this.BlockPos == 256)
        {
          for (int i = 0; i < 256; i++) {
            this.dataOut.writeByte(this.Block[i]);
          }
          this.Block[0] = 0;
          this.BlockPos = 1;
        }
      }

      return true;
    }
    catch (Exception _ex) {
    }
    return false;
  }

  public void CalcSpecialCodes()
  {
    this.clearCode = ((short)(1 << this.sOriginalCodeSize));
    for (short word0 = 0; word0 < this.clearCode; word0 = (short)(word0 + 1))
    {
      this.prefix[word0] = word0;
      this.codeCharacter[word0] = ((short)(byte)word0);
    }

    this.endCode = ((short)(this.clearCode + 1));
    this.freeSlot = ((short)(this.clearCode + 2));
    this.sActCodeSize = ((short)(this.sOriginalCodeSize + 1));
  }

  public boolean writeHeader()
  {
    try
    {
      this.dataOut.writeBytes("GIF87a");
    }
    catch (Exception _ex)
    {
      return false;
    }
    return true;
  }

  public boolean writeGlobalPalette()
  {
    int j = 1;
    for (int i = this.palSize - 1; i >> 1 > 0; ) {
      j++;
    }
    try
    {
      for (int k = 0; k < this.palSize; k++)
      {
        Color color = new Color(this.palArr[k]);
        this.dataOut.writeByte(color.getRed());
        this.dataOut.writeByte(color.getGreen());
        this.dataOut.writeByte(color.getBlue());
      }

      for (int l = this.palSize; l < 1 << j; l++)
      {
        Color color1 = new Color(this.palArr[0]);
        this.dataOut.writeByte(color1.getRed());
        this.dataOut.writeByte(color1.getGreen());
        this.dataOut.writeByte(color1.getBlue());
      }

    }
    catch (Exception _ex)
    {
      return false;
    }
    return true;
  }

  public boolean writeImageDescriptor()
  {
    try
    {
      byte byte0 = (byte)(this.flagLSD & 0x7);
      this.dataOut.writeByte(44);
      this.dataOut.writeChar(0);
      this.dataOut.writeChar(0);
      this.dataOut.writeChar(MSBtoLSB(this.imgWidth));
      this.dataOut.writeChar(MSBtoLSB(this.imgHeight));
      this.dataOut.writeByte(byte0);
    }
    catch (Exception _ex)
    {
      return false;
    }
    return true;
  }

  public boolean writeLSD()
  {
    byte byte0 = 0;
    int i = this.palSize - 1;
    try
    {
      while (i >> 1 > 0)
        byte0 = (byte)(byte0 + 1);
      this.flagLSD = ((byte)((byte0 + 8 << 4) + byte0));
      this.dataOut.writeChar(MSBtoLSB(this.imgWidth));
      this.dataOut.writeChar(MSBtoLSB(this.imgHeight));
      this.dataOut.writeByte(this.flagLSD);
      this.dataOut.writeByte(0);
      this.dataOut.writeByte(0);
    }
    catch (Exception _ex)
    {
      return false;
    }
    return true;
  }

  public boolean closeGif()
  {
    try
    {
      this.dataOut.writeByte(59);
      this.output.close();
      return true;
    }
    catch (Exception _ex) {
    }
    return false;
  }
}